/*
 * MainGame.h
 *	GLMoblet type, Singleton works as a base class and access to managers
 *  Created on: Oct 7, 2012
 *      Author: pigmal
 */

#ifndef MAINGAME_H_
#define MAINGAME_H_

#include <maapi.h>
#include <mastdlib.h>
#include <mavsprintf.h>
#include <MAUtil/Moblet.h>
#include <MAUtil/GLMoblet.h>
#include <GLES/gl.h>
#include "MAHeaders.h" // for resources
#include "MoBox2d/include/MoBox2D/Box2D.h"
#include<glm.hpp>

#include"Sprite.h"

using namespace MAUtil;

/**
 * Moblet to be used as a template for an Open GL application.
 * The template program draws a rotating quad. Touch the
 * screen to change the depth coordinate.
 */
class MainGame : public GLMoblet
{
public:

	~MainGame();

	static MainGame	*GetInstance();

	// ================== Event methods ==================

	/**
	 * Called when a fullscreen window with an OpenGL context
	 * has been created and is ready to be used.
	 */
	void init()
	{
		// Set the GL viewport to be the entire MoSync screen.
		setViewport(
			EXTENT_X(maGetScrSize()),
			EXTENT_Y(maGetScrSize()));

		// Initialize OpenGL.
		initGL();

		b2Vec2 gravity(0.0f, -10.0f);
		bool doSleep = true;
		b2World world(gravity, doSleep);

		// Call draw 60 times per second.
		setPreferredFramesPerSecond(60);
	}

	/**
	 * Called when the application should render the model.
	 * Use method setPreferredFramesPerSecond to set the
	 * desired frame rate.
	 */
	void draw()
	{
		// Compute rotation.
		GLfloat rotation = (maGetMilliSecondCount() - mStartTime) * -0.05f;

		// Render scene.
		draw(mDepth, rotation);
	}

	/**
	 * Called when a key is pressed.
	 */
	void keyPressEvent(int keyCode, int nativeCode)
	{
		if (MAK_BACK == keyCode || MAK_0 == keyCode)
		{
			// Call close to exit the application.
			close();
		}
	}

	/**
	 * Called on a touch down event.
	 */
	void pointerPressEvent(MAPoint2d point)
	{
		computeZoomFactor(point);
	}

	/**
	 * Called on a touch drag event.
	 */
	void pointerMoveEvent(MAPoint2d point)
	{
		computeZoomFactor(point);
	}

private:

	static MainGame *mainGame;

	// ================== Constructor ==================

	/**
	 * Initialize rendering parameters.
	 */
	MainGame() :
		GLMoblet(GLMoblet::GL1),
		mDepth(5.0f),
		mStartTime(maGetMilliSecondCount())
	{
	}

	// ================== OpenGL/rendering methods ==================

	/**
	 * Standard OpenGL initialization.
	 */
	void initGL()
	{
		glEnable(GL_CULL_FACE);
		glEnable(GL_TEXTURE_2D);
		glShadeModel(GL_SMOOTH);
		glClearDepthf(1.0f);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

		Texture texture;
		texture.Setup(SQUARE_TEXTURE, GL_LINEAR);

		sprite.Init(NULL, &texture);

//		// Create an OpenGL 2D texture from the resource.
//		glEnable(GL_TEXTURE_2D);
//		glGenTextures(1, &mBoxTextureHandle);
//		glBindTexture(GL_TEXTURE_2D, mBoxTextureHandle);
//		maOpenGLTexImage2D(SQUARE_TEXTURE);
//
//		// Set texture parameters.
//		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	/**
	 * Setup the projection matrix.
	 */
	void setViewport(int width, int height)
	{
		// Protect against divide by zero.
		if (0 == height)
		{
			height = 1;
		}

		// Set viewport and perspective.
		glViewport(0, 0, (GLint)width, (GLint)height);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		GLfloat ratio = (GLfloat)width / (GLfloat)height;
		gluPerspective(45.0f, ratio, 0.1f, 100.0f);
	}

	/**
	 * Render the model (draws a quad).
	 */
	void draw(GLfloat z, GLfloat rotation)
	{
	    // Set the background color to be used when clearing the screen.
	    glClearColor(0.3f, 0.0f, 0.0f, 1.0f);

	    // Clear the screen and the depth buffer.
	    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	    // Use the model matrix.
	    glMatrixMode(GL_MODELVIEW);

	    // Reset the model matrix.
	    glLoadIdentity();

	    // Move into the screen 5 units.
	    glTranslatef(0.0f, 0.0f, -z);

	    // Select the texture to use when rendering the box.
	    //glBindTexture(GL_TEXTURE_2D, mBoxTextureHandle);

	    sprite.update();
//		 Define quad vertices.
//	    GLfloat vcoords[4][3];
//	     Array used for texture coordinates.
//	    GLfloat tcoords[4][2];
//	     Set pointers to vertex coordinates and texture coordinates.
//	    glVertexPointer(3, GL_FLOAT, 0, vcoords);
//	    glTexCoordPointer(2, GL_FLOAT, 0, tcoords);

	    // Enable vertex and texture coord arrays.
	    //glEnableClientState(GL_VERTEX_ARRAY);
//	    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

//	    vcoords[0][0] = -1.0f; vcoords[0][1] = -1.0f; vcoords[0][2] = 0.0f;	//A
//	    vcoords[1][0] = 1.0f;  vcoords[1][1] = -1.0f; vcoords[1][2] = 0.0f;	//D
//	    vcoords[2][0] = 1.0f;  vcoords[2][1] = 1.0f;  vcoords[2][2] = 0.0f;	//C
//	    vcoords[3][0] = -1.0f; vcoords[3][1] = 1.0f;  vcoords[3][2] = 0.0f;	//B


	    // Define the front face of the box.
//	    tcoords[0][0] = 1.0f;  tcoords[0][1] = 1.0f;	//C
//	    tcoords[1][0] = 0.0f;  tcoords[1][1] = 1.0f;	//B
//	    tcoords[2][0] = 0.0f;  tcoords[2][1] = 0.0f;	//A
//	    tcoords[3][0] = 1.0f;  tcoords[3][1] = 0.0f;	//D

//	    // Array used to convert from QUAD to TRIANGLE_STRIP.
//	    // QUAD is not available on the OpenGL implementation
//	    // we are using.
//	    GLubyte indices[4] = {0, 1, 3, 2};
//
//	    // This draws one textured plane using a strip of two triangles.
//	    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
//	    // Disable texture and vertex arrays.
//	    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//	    glDisableClientState(GL_VERTEX_ARRAY);
//	    // Wait (blocks) until all GL drawing commands to finish.
	    glFinish();
	}

	/**
	 * Compute the visible size of the quad by
	 * setting the depth coordinate.
	 */
	void computeZoomFactor(MAPoint2d point)
	{
		float screenHeight = EXTENT_Y(maGetScrSize());
		mDepth = 20.0f / screenHeight * point.y;
	}

	/**
	 * Standard OpenGL utility function for setting up the
	 * perspective projection matrix.
	 */
	void gluPerspective(
		GLfloat fovy,
		GLfloat aspect,
		GLfloat zNear,
		GLfloat zFar)
	{
		//const float M_PI = 3.14159;

		GLfloat ymax = zNear * tan(fovy * 3.14159 / 360.0);
		GLfloat ymin = -ymax;
		GLfloat xmin = ymin * aspect;
		GLfloat xmax = ymax * aspect;

		glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);
	}

private:

	// ================== Instance variables ==================

	/** Time stamp used to calculate rotation. */
	GLfloat mStartTime;

	/** Handle to the texture. */
	GLuint mBoxTextureHandle;

	/** Z-coordinate. */
	GLfloat mDepth;

	Sprite sprite;
};
#endif /* MAINGAME_H_ */

